/*
 * spring-security-jwt - spring-security-jwt
 * Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.topiam.employee.sample.jwt.authentication;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;

/**
 * JWT 工具类
 *
 * @author TopIAM
 * Created by support@topiam.cn on  2023/02/12 20:58
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class JwtUtils {
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    public static PublicKey readPublicKey(String pem) throws CertificateException {
        return getCertificate(pem.getBytes(StandardCharsets.UTF_8)).getPublicKey();
    }

    public static X509Certificate getCertificate(byte[] der) throws CertificateException {
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(der));
    }

    /**
     * 根据 Token 获取用户名
     *
     * @param token     {@link String} jwt token
     * @param publicKey {@link PublicKey} 公钥
     * @return {@link Claims}
     */
    public static Claims validateToken(String token, PublicKey publicKey) {
        try {
            JwtParser jwtParser = Jwts.parser().verifyWith(publicKey).build();
            return jwtParser.parseSignedClaims(token).getPayload();
        } catch (ExpiredJwtException e) {
            log.error("令牌过期", e);
        } catch (UnsupportedJwtException e) {
            log.error("处理令牌格式异常", e);
        } catch (MalformedJwtException e) {
            log.error("处理无效签名/claims", e);
        } catch (SignatureException e) {
            log.error("处理签名验证失败", e);
        } catch (IllegalArgumentException e) {
            log.error("处理空令牌异常", e);
        }
        throw new ValidateTokenException();
    }

    /**
     * 根据 Token 获取用户名
     *
     * @param token     {@link String}
     * @param publicKey {@link PublicKey}
     * @return {@link String} 用户名
     */
    public static String getUserNameFromToken(String token, PublicKey publicKey) {
        String username;
        try {
            Claims claims = validateToken(token, publicKey);
            username = claims.getSubject();
        } catch (Exception e) {
            username = null;
        }
        return username;
    }
}
